home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src890906.arc
/
ALLOC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-19
|
12KB
|
507 lines
/* memory allocation routines
*
* Adapted from alloc routine in K&R; memory statistics and interrupt
* protection added for use with net package. Must be used in place of
* standard Turbo-C library routines because the latter check for stack/heap
* collisions. This causes erroneous failures because process stacks are
* allocated off the heap.
*/
#include <stdio.h>
#include <dos.h>
#include <alloc.h>
#include "global.h"
#include "proc.h"
static unsigned long memfail; /* Count of allocation failures */
static unsigned long allocs; /* Total allocations */
static unsigned long frees; /* Total frees */
static unsigned long garbage; /* Total calls to free with garbage arg */
#ifdef LARGEDATA
/**** LARGE DATA MODEL VERSION ****/
union header {
struct {
union header huge *ptr;
unsigned long size;
} s;
long l[2];
};
typedef union header HEADER;
#define NULLHDR (HEADER huge *)NULL
#define ABLKSIZE (sizeof (HEADER))
static HEADER huge *morecore __ARGS((unsigned nu));
static HEADER base;
static HEADER huge *allocp = NULLHDR;
static char huge *heapbase;
static char huge *heaptop;
static unsigned long heapsize;
/* Allocate block of 'nb' bytes */
void *
malloc(nb)
unsigned nb;
{
register HEADER huge *p, huge *q;
register unsigned nu;
char i_state;
if(nb == 0)
return NULL;
i_state = dirps();
/* Round up to full block, then add one for header */
nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 1;
if ((q = allocp) == NULLHDR){
base.s.ptr = allocp = q = &base;
base.s.size = 1;
}
for (p = q->s.ptr; ; q = p, p = p->s.ptr){
if (p->s.size >= nu){
/* This chunk is at least as large as we need */
if (p->s.size <= nu + 1){
/* This is either a perfect fit (size == nu)
* or the free chunk is just one unit larger.
* In either case, alloc the whole thing,
* because there's no point in keeping a free
* block only large enough to hold the header.
*/
q->s.ptr = p->s.ptr;
} else {
/* Carve out piece from end of entry */
p->s.size -= nu;
p += p->s.size;
p->s.size = nu;
}
allocp = q;
p->s.ptr = p; /* for auditing */
restore(i_state);
allocs++;
return (void *)(p + 1);
}
/* Don't call the system for more memory if interrupts
* are off; we're probably in an interrupt handler
*/
if (p == allocp && (!i_state || (p = morecore(nu)) == NULLHDR)){
memfail++;
restore(i_state);
return NULL;
}
}
}
/* Get more memory from the system and put it on the heap */
static HEADER huge *
morecore(nu)
unsigned nu;
{
register char huge *cp;
register HEADER huge *up;
/* Before calling main, the Turbo startup routines call malloc to
* save the environment. In turn this calls morecore, all before we
* get a chance to call grabcore. Hence the null test for heaptop.
*/
if(heaptop != NULL && (char huge *)sbrk(0) >= heaptop)
return NULLHDR; /* Don't let it overwrite stack */
if ((int)(cp = (char huge *)sbrk(nu * ABLKSIZE)) == -1)
return NULLHDR;
up = (HEADER *)cp;
up->s.size = nu;
up->s.ptr = up; /* satisfy audit */
free((void *)(up + 1));
return allocp;
}
/* Grab the specified amount of memory from the system, if available,
* and place it on the heap
*/
unsigned long
grabcore(size)
unsigned long size;
{
register HEADER huge *up;
/* Find out where the break is */
heapbase = (char huge *)sbrk(0);
/* Now try to get the requested amount, or as much as possible
* below that
*/
while((int)brk(heapbase+size) == -1)
size -= 256;
heapsize = size;
heaptop = (char huge *)sbrk(0);
/* Initialize the heap pointers */
if (allocp == NULLHDR){
base.s.ptr = allocp = &base;
base.s.size = 1;
}
up = (HEADER *)heapbase;
up->s.size = heapsize / sizeof(HEADER);
up->s.ptr = up; /* satisfy audit */
free((void *)(up + 1));
return heapsize;
}
/* Put memory block back on heap */
void
free(blk)
void *blk;
{
register HEADER huge *p, huge *q;
unsigned short huge *ptr;
char i_state;
if(blk == NULL)
return; /* Required by ANSI */
i_state = dirps();
p = (HEADER huge *)blk - 1;
/* Audit check */
if(p->s.ptr != p){
ptr = (unsigned short *)&blk;
printf("WARNING!! freeing garbage (0x%lx) pc = 0x%x %x proc %s\n",ptol(blk),
ptr[-1],ptr[-2],Curproc->name);
garbage++;
restore(i_state);
return;
}
/* Search the free list looking for the right place to insert */
for(q = allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
/* Highest address on circular list? */
if(q >= q->s.ptr && (p > q || p < q->s.ptr))
break;
}
if(p + p->s.size == q->s.ptr){
/* Combine with front of this entry */
p->s.size += q->s.ptr->s.size;
p->s.ptr = q->s.ptr->s.ptr;
} else {
/* Link to front of this entry */
p->s.ptr = q->s.ptr;
}
if(q + q->s.size == p){
/* Combine with end of this entry */
q->s.size += p->s.size;
q->s.ptr = p->s.ptr;
} else {
/* Link to end of this entry */
q->s.ptr = p;
}
allocp = q;
restore(i_state);
frees++;
}
#ifdef notdef /* Not presently used */
/* Move existing block to new area */
void *
realloc(area,size)
void *area;
unsigned size;
{
unsigned osize;
HEADER huge *hp;
char huge *cp;
char i_state;
hp = ((HEADER *)area) - 1;
osize = (hp->s.size -1) * ABLKSIZE;
/* Make sure nobody else comes in and takes it */
i_state = dirps();
free(area);
if((cp = malloc(size)) != NULL && cp != area)
memcpy((char *)cp,(char *)area,size>osize? osize : size);
restore(i_state);
return cp;
}
#endif
/* Allocate block of cleared memory */
void *
calloc(nelem,size)
unsigned nelem; /* Number of elements */
unsigned size; /* Size of each element */
{
register unsigned i;
register char *cp;
i = nelem * size;
if((cp = malloc(i)) != NULL)
memset(cp,0,i);
return cp;
}
/* Print free list map */
int
memstat(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
HEADER huge *p;
unsigned long total = 0;
int i = 0;
for(p = base.s.ptr;p != &base;p = p->s.ptr){
total += p->s.size * sizeof(HEADER);
printf("%5lx %6lu",ptol((void *)p),p->s.size * ABLKSIZE);
if(++i == 4){
i = 0;
putchar('\n');
} else
printf(" | ");
}
if(i != 0)
putchar('\n');
printf("heap base %lx size %lu avail %lu (%lu%%) coreleft %lu\n",
ptol((void *)heapbase),heapsize,total,100L*total/heapsize,
coreleft());
printf("allocs %lu frees %lu (diff %lu) mfails %lu garbage %lu\n",
allocs,frees,allocs-frees,memfail,garbage);
return 0;
}
#else /* not LARGEDATA */
/**** SMALL DATA MODEL VERSION ****/
union header {
struct {
union header *ptr;
unsigned int size;
} s;
long l;
};
typedef union header HEADER;
#define NULLHDR (HEADER *)NULL
#define ABLKSIZE (sizeof (HEADER))
static HEADER *morecore __ARGS((unsigned nu));
static HEADER base;
static HEADER *allocp = NULLHDR;
static char *heapbase;
static char *heaptop;
static unsigned long heapsize;
/* Allocate block of 'nb' bytes */
void *
malloc(nb)
unsigned nb;
{
register HEADER *p, *q;
register unsigned nu;
char i_state;
if(nb == 0)
return NULL;
i_state = dirps();
/* Round up to full block, then add one for header */
nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 1;
if ((q = allocp) == NULLHDR){
base.s.ptr = allocp = q = &base;
base.s.size = 1;
}
for (p = q->s.ptr; ; q = p, p = p->s.ptr){
if (p->s.size >= nu){
/* This chunk is at least as large as we need */
if (p->s.size <= nu + 1){
/* This is either a perfect fit (size == nu)
* or the free chunk is just one unit larger.
* In either case, alloc the whole thing,
* because there's no point in keeping a free
* block only large enough to hold the header.
*/
q->s.ptr = p->s.ptr;
} else {
/* Carve out piece from end of entry */
p->s.size -= nu;
p += p->s.size;
p->s.size = nu;
}
allocp = q;
p->s.ptr = p; /* for auditing */
restore(i_state);
allocs++;
return (void *)(p + 1);
}
if (p == allocp && (p = morecore(nu)) == NULLHDR){
memfail++;
restore(i_state);
return NULL;
}
}
}
/* Get more memory from the system and put it on the heap */
static HEADER *
morecore(nu)
unsigned nu;
{
register char *cp;
register HEADER *up;
/* Before calling main, the Turbo startup routines call malloc to
* save the environment. In turn this calls morecore, all before we
* get a chance to call grabcore. Hence the null test for heaptop.
*/
if(heaptop != NULL && (char *)sbrk(0) >= heaptop)
return NULLHDR; /* Don't let it overwrite stack */
if ((int)(cp = (char *)sbrk(nu * ABLKSIZE)) == -1)
return NULLHDR;
up = (HEADER *)cp;
up->s.size = nu;
up->s.ptr = up; /* satisfy audit */
free((void *)(up + 1));
return allocp;
}
/* Grab the specified amount of memory from the system, if available,
* and place it on the heap
*/
unsigned long
grabcore(size)
unsigned long size;
{
register HEADER *up;
/* Find out where the break is */
heapbase = (char *)sbrk(0);
/* Now try to push it as high as possible */
while(brk(heapbase+size) == -1)
size -= 16;
heapsize = size;
heaptop = (char *)sbrk(0);
/* Initialize the heap pointers */
if (allocp == NULLHDR){
base.s.ptr = allocp = &base;
base.s.size = 1;
}
up = (HEADER *)heapbase;
up->s.size = heapsize / sizeof(HEADER);
up->s.ptr = up; /* satisfy audit */
free((void *)(up + 1));
return heapsize;
}
/* Put memory block back on heap */
void
free(blk)
void *blk;
{
register HEADER *p,*q;
unsigned short *ptr;
char i_state;
if(blk == NULL)
return; /* Required by ANSI */
i_state = dirps();
p = (HEADER *)blk - 1;
/* Audit check */
if(p->s.ptr != p){
ptr = (unsigned short *)&blk;
printf("WARNING!! freeing garbage (0x%lx) pc = 0x%x %x proc %s\n",ptol(blk),
ptr[-1],ptr[-2],Curproc->name);
garbage++;
restore(i_state);
return;
}
/* Search the free list looking for the right place to insert */
for(q = allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
/* Highest address on circular list? */
if(q >= q->s.ptr && (p > q || p < q->s.ptr))
break;
}
if(p + p->s.size == q->s.ptr){
/* Combine with front of this entry */
p->s.size += q->s.ptr->s.size;
p->s.ptr = q->s.ptr->s.ptr;
} else {
/* Link to front of this entry */
p->s.ptr = q->s.ptr;
}
if(q + q->s.size == p){
/* Combine with end of this entry */
q->s.size += p->s.size;
q->s.ptr = p->s.ptr;
} else {
/* Link to end of this entry */
q->s.ptr = p;
}
allocp = q;
restore(i_state);
frees++;
}
#ifdef notdef /* Not presently used */
/* Move existing block to new area */
void *
realloc(area,size)
void *area;
unsigned size;
{
unsigned osize;
HEADER *hp;
char *cp;
char i_state;
hp = ((HEADER *)area) - 1;
osize = (hp->s.size -1) * ABLKSIZE;
/* Make sure nobody else comes in and takes it */
i_state = dirps();
free(area);
if((cp = malloc(size)) != NULL && cp != area)
memcpy((char *)cp,(char *)area,size>osize? osize : size);
restore(i_state);
return cp;
}
#endif
/* Allocate block of cleared memory */
void *
calloc(nelem,size)
unsigned nelem; /* Number of elements */
unsigned size; /* Size of each element */
{
register unsigned i;
register char *cp;
i = nelem * size;
if((cp = malloc(i)) != NULL)
memset(cp,0,i);
return cp;
}
/* Print free list map */
memstat(argc,argv,envp)
int argc;
char *argv[];
void *envp;
{
HEADER *p;
unsigned long total = 0;
int i = 0;
for(p = base.s.ptr;p != &base;p = p->s.ptr){
total += p->s.size * sizeof(HEADER);
printf("%5lx %6lu",ptol(p),(long)p->s.size * ABLKSIZE);
if(++i == 4)
putchar('\n');
else
printf(" | ");
}
if(i != 0)
putchar('\n');
printf("heap base %lx size %lu avail %lu (%lu%%) coreleft %u\n",
ptol((void *)heapbase),heapsize,total,100L*total/heapsize,coreleft());
printf("allocs %lu frees %lu (diff %lu) mfails %lu garbage %lu\n",
allocs,frees,allocs-frees,memfail,garbage);
}
#endif